/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package BuildGrid;

import static Edge.BuildEdge.All_Vertex;
import static Edge.BuildEdge.dvalue;
import Edge.Edge;
import Graph.Car;
import Graph.Vertex;
import Graph.Vnode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

/**
 *
 * @author 江南才俊周涛涛
 */
public class Grid {

    public HashMap<Integer, Vertex> vertexs = new HashMap<Integer, Vertex>();
    public List<Vertex> bord = new ArrayList<Vertex>();
    public List<Vertex> lvertexs = new ArrayList<Vertex>(50);//lvertexs和vertex存的是同样的结点，只是存储方式不同，lvertex方便遍历 （ vertexs.get(i)= lvertexs.get(vertexs.get(i).grid_index)
    public List<Integer> names = new ArrayList<Integer>(50);//内部结点的名字，方便生成汽车时，按正态分布生成
    int x;//格子是第x行
    int y;//第y列
    public int size = 0;//该格子中结点的数量
    int border_index = 0;//内部结点的数量，即第一个边界点的下标
    public List<Edge> edges = new ArrayList<Edge>(80);//格子中的道路,如果知道道路的大致数量，可以提前给予内存
    int query_index = -1;
    public HashMap<Integer, HashSet<Vnode>> neighbors = new HashMap<Integer, HashSet<Vnode>>();//格子中的所有边
    public HashSet<Integer> current_names = new HashSet<Integer>();

    public double minidis[][];//minidis[i][j]为lvertexs.get(i)到lvertexs.get(j)的距离

    public Grid(int i, int j) {
        x = i;
        y = j;
    }

    //添加结点（非边界点）
    public void put_vertex(int name, Vertex temp) {
        temp.grid_index = border_index++;
        size++;
        lvertexs.add(temp);
        vertexs.put(name, temp);
        HashSet<Vnode> hs = new HashSet<Vnode>();
        neighbors.put(name, hs);
    }

    //添加边界点
    public void putmap(int name, Vertex temp) {
        temp.grid_index = size++;
        lvertexs.add(temp);
        vertexs.put(name, temp);
        HashSet<Vnode> hs = new HashSet<Vnode>();
        neighbors.put(name, hs);
        current_names.add(name);
        bord.add(temp);
    }

    //构图
    public void buildgraph() {
        
        Floyd();
        //System.out.println("aa");
        SaveBorder();
        //System.out.println("bb");

    }

    public void init_query_dvalue(int query_name) {//初始化dvalue
        if (query_index == -1) {
            query_index = vertexs.get(query_name).grid_index;
        }

        for (int i = 0; i < size; i++) {
            dvalue[lvertexs.get(i).Vertex_name] = minidis[query_index][i];
        }
    }

    public void set_init_neighbor(List<Integer> current) {
        current.addAll(current_names);
        for (Integer names : current_names) {
            All_Vertex.get(names).neighbors.addAll(neighbors.get(names));
        }
    }

    public void set_init_neighbor(HashSet<Integer> current) {
        current.addAll(current_names);
        for (Integer names : current_names) {
            All_Vertex.get(names).neighbors.addAll(neighbors.get(names));
        }
    }

    public void set_neighbor(HashSet<Integer> current) {
        current.addAll(current_names);
        for (Integer names : current_names) {
            All_Vertex.get(names).neighbors.addAll(neighbors.get(names));
        }
    }



    //将相连的边界点与边界点之间， 以及内部结点与边界点之间，分别连接起来
    private void SaveBorder() {
        for (int i = border_index; i < size; i++) {
            int name = lvertexs.get(i).Vertex_name;
            for (int j = i + 1; j < size; j++) {
                if (minidis[i][j] != -1) {
                    int name2 = lvertexs.get(j).Vertex_name;
                    Vnode vf = new Vnode(name, minidis[i][j]);
                    Vnode vt = new Vnode(name2, minidis[i][j]);
                    neighbors.get(name).add(vt);
                    neighbors.get(name2).add(vf);
                }
            }
            for (int k = 0; k < border_index; k++) {
                if (minidis[i][k] != -1) {
                    int name2 = lvertexs.get(k).Vertex_name;
                    Vnode vt = new Vnode(name, minidis[i][k]);
                    neighbors.get(name2).add(vt);
                    if (minidis[i][k] < All_Vertex.get(name2).max_dis) {
                        All_Vertex.get(name2).max_dis = minidis[i][k];

                    }
                }
            }
        }
    }

    //添加查询点
    public void addQuery(int name) {
        query_index = vertexs.get(name).grid_index;
        for (Integer names : current_names) {
            double dis = minidis[query_index][vertexs.get(names).grid_index];
            if (dis != -1) {
                Vnode temp = new Vnode(name, dis);
                neighbors.get(names).add(temp);
            }
        }
    }

    //添加汽车
    public void addActive(int name, Car c) {
        int index = vertexs.get(name).grid_index;

        if (!All_Vertex.get(name).isactive) {
            All_Vertex.get(name).isactive = true;
            current_names.add(name);
            for (int i = 0; i < index; i++) {
                if (minidis[i][index] != -1) {
                    int name2 = lvertexs.get(i).Vertex_name;
                    Vnode temp = new Vnode(name, minidis[i][index]);
                    neighbors.get(name2).add(temp);
                    Car cc = new Car(c);
                    cc.query_dis = minidis[i][index] + cc.dis;
                    All_Vertex.get(name).add_kCar(cc);
                }
            }
            for (int i = index + 1; i < border_index; i++) {
                if (minidis[i][index] != -1) {
                    int name2 = lvertexs.get(i).Vertex_name;
                    Vnode temp = new Vnode(name, minidis[i][index]);
                    neighbors.get(name2).add(temp);

                    Car cc = new Car(c);
                    cc.query_dis = minidis[i][index] + cc.dis;
                    All_Vertex.get(name).add_kCar(cc);
                }
            }

            for (int i = border_index; i < size; i++) {
                if (minidis[i][index] != -1) {
                    int name2 = lvertexs.get(i).Vertex_name;
                    Vnode temp = new Vnode(name, minidis[i][index]);
                    neighbors.get(name2).add(temp);
                }
            }
        } else {
            for (int i = 0; i < index; i++) {
                if (minidis[i][index] != -1) {
                    Car cc = new Car(c);
                    cc.query_dis = minidis[i][index] + cc.dis;
                    All_Vertex.get(name).add_kCar(cc);

                }
            }
            for (int i = index + 1; i < border_index; i++) {
                if (minidis[i][index] != -1) {
                    Car cc = new Car(c);
                    cc.query_dis = minidis[i][index] + cc.dis;
                    All_Vertex.get(name).add_kCar(cc);
                }
            }
        }
    }
    
    

    //删除活跃点name
    public void deleteActive(int name) {
        current_names.remove((Integer) (name));
        Vnode del = new Vnode(name, 0);//因为Vnode的equal只跟名字有关，所以只要name相同，就可以remove
        for (Vnode v : neighbors.get(name)) {
            neighbors.get(v.name).remove(del);
        }
    }

    //floyd算法；计算minidis 点与点之间最短距离
    private void Floyd() {
        minidis = new double[size][size];
        for (int i = 0; i < size; i++) {
            minidis[i][i] = -1;
            for (int j = i + 1; j < size; j++) {
                minidis[i][j] = -1;
                minidis[j][i] = -1;
            }
        }

        for (int i = 0; i < edges.size(); i += 2) {//因为两条边是对称的，所以一次执行两条，加快效率
            Edge temp = edges.get(i);
            connect(vertexs.get(temp.from).grid_index, vertexs.get(temp.to).grid_index, temp.distence);

        }

        for (int k = 0; k < size; k++) {
            for (int i = 0; i < size; i++) {
                for (int j = i + 1; j < size; j++) {
                    if (minidis[i][k] != -1 && minidis[k][j] != -1 && (minidis[i][j] > (minidis[i][k] + minidis[k][j]) || minidis[i][j] == -1)) {
                        minidis[i][j] = minidis[i][k] + minidis[k][j];
                        minidis[j][i] = minidis[i][j];
                    }
                }
            }
        }
    }

    //Floyd中赋值
    private void connect(int from, int to, double distence) {
        minidis[from][to] = distence;
        minidis[to][from] = distence;
    }
}
